package com.example.redis.adviced.redis.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.redis.adviced.redis.bean.Employee;
import com.example.redis.adviced.redis.mapper.EmployeeMapper;
import com.example.redis.adviced.redis.service.EmployeeService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.concurrent.TimeUnit;

@Service
public class EmployeeServiceImpl extends ServiceImpl<EmployeeMapper, Employee> implements EmployeeService {

    @Autowired
    private EmployeeMapper employeeMapper;

    @Autowired
    private RedisTemplate redisTemplate;

    private static final String CACHE_KEY_EMPLOYEE = "employee:";

    @Override
    public Employee getEmployeeById(Integer id) {
        Employee employee;
        String key = CACHE_KEY_EMPLOYEE + id;
        if ((employee = (Employee) redisTemplate.opsForValue().get(key)) != null) {
            return employee;
        }
        // 采用双检加锁从策略：
        //      当缓存失效时，通过加锁机制确保只有一个线程/进程去查询数据库并重建缓存，其他请求等待，
        //      从而避免数据库被并发请求冲垮
        // 避免缓存击穿问题
        synchronized (this) {
            employee = (Employee) redisTemplate.opsForValue().get(key);
            if (employee == null) {
                if ((employee = employeeMapper.getEmployeeById(id)) == null)
                    return null;
                else
                    redisTemplate.opsForValue().setIfAbsent(key, employee, 7L, TimeUnit.DAYS);
            }
            return employee;
        }
    }

    @Override
    public void deleteEmployeeById(Integer id) {
        String key = CACHE_KEY_EMPLOYEE + id;
        redisTemplate.delete(key);

        employeeMapper.deleteEmployeeById(id);

        // 延迟双删策略
        try {
            TimeUnit.SECONDS.sleep(2);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        redisTemplate.delete(key);
    }
}
